]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Searcher.c
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Searcher.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.20 2004/10/19 21:33:18 cheshire
27 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
28 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
29 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
30
31 Revision 1.19 2004/09/17 01:08:50 cheshire
32 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
33 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
34 declared in that file are ONLY appropriate to single-address-space embedded applications.
35 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
36
37 Revision 1.18 2004/09/16 21:59:16 cheshire
38 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
39
40 Revision 1.17 2004/06/10 04:37:27 cheshire
41 Add new parameter in mDNS_GetDomains()
42
43 Revision 1.16 2004/03/12 21:30:25 cheshire
44 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
45 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
46
47 Revision 1.15 2004/01/24 23:55:15 cheshire
48 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
49
50 Revision 1.14 2003/11/14 21:27:09 cheshire
51 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
52 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
53
54 Revision 1.13 2003/08/14 02:19:54 cheshire
55 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
56
57 Revision 1.12 2003/08/12 19:56:24 cheshire
58 Update to APSL 2.0
59
60 */
61
62 #include <stdio.h> // For printf()
63 #include <Events.h> // For WaitNextEvent()
64 #include <SIOUX.h> // For SIOUXHandleOneEvent()
65
66 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
67 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
68
69 typedef struct
70 {
71 OTLIFO serviceinfolist;
72 Boolean headerPrinted;
73 Boolean lostRecords;
74 } SearcherServices;
75
76 typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo;
77
78 // These don't have to be globals, but their memory does need to remain valid for as
79 // long as the search is going on. They are declared as globals here for simplicity.
80 #define RR_CACHE_SIZE 1000
81 static CacheRecord rrcachestorage[RR_CACHE_SIZE];
82 static mDNS mDNSStorage;
83 static mDNS_PlatformSupport PlatformSupportStorage;
84 static SearcherServices services;
85 static DNSQuestion browsequestion, domainquestion;
86
87 // PrintServiceInfo prints the service information to standard out
88 // A real application might want to do something else with the information
89 static void PrintServiceInfo(SearcherServices *services)
90 {
91 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
92
93 while (link)
94 {
95 linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link);
96 ServiceInfo *s = &ls->i;
97
98 if (!services->headerPrinted)
99 {
100 printf("%-55s Type Domain IP Address Port Info\n", "Name");
101 services->headerPrinted = true;
102 }
103
104 if (ls->dom)
105 {
106 char c_dom[MAX_ESCAPED_DOMAIN_NAME];
107 ConvertDomainNameToCString(&s->name, c_dom);
108 if (ls->add) printf("%-55s available for browsing\n", c_dom);
109 else printf("%-55s no longer available for browsing\n", c_dom);
110 }
111 else
112 {
113 domainlabel name;
114 domainname type, domain;
115 char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20];
116 DeconstructServiceName(&s->name, &name, &type, &domain);
117 ConvertDomainLabelToCString_unescaped(&name, c_name);
118 ConvertDomainNameToCString(&type, c_type);
119 ConvertDomainNameToCString(&domain, c_dom);
120 sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
121
122 printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
123 if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo);
124 else printf("Removed\n");
125 }
126
127 link = link->fNext;
128 OTFreeMem(ls);
129 }
130 }
131
132 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
133 // enqueues a record for PrintServiceInfo() to print.
134 // Note, a browsing application would *not* normally need to get all this information --
135 // all it needs is the name, to display to the user.
136 // Finding out the address, port, and txtinfo should be deferred to the time that the user
137 // actually needs to contact the service to use it.
138 static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
139 {
140 SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext;
141 linkedServiceInfo *info = (linkedServiceInfo *)(query->info);
142 if (query->info->ip.type == mDNSAddrType_IPv4)
143 {
144 mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient
145 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
146 OTFreeMem(query);
147 }
148 }
149
150 // When a new named instance of a service is found, FoundInstance() is called.
151 // In this sample code we turn around and immediately issue a query to resolve that service name to
152 // find its address, port, and txtinfo, but a normal browing application would just display the name.
153 static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
154 {
155 #pragma unused (question)
156 SearcherServices *services = (SearcherServices *)question->QuestionContext;
157 linkedServiceInfo *info;
158
159 debugf("FoundInstance %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
160
161 if (answer->rrtype != kDNSType_PTR) return;
162 if (!services) { debugf("FoundInstance: services is NULL"); return; }
163
164 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
165 if (!info) { services->lostRecords = true; return; }
166
167 info->i.name = answer->rdata->u.name;
168 info->i.InterfaceID = answer->InterfaceID;
169 info->i.ip.type = mDNSAddrType_IPv4;
170 info->i.ip.ip.v4 = zerov4Addr;
171 info->i.port = zeroIPPort;
172 info->add = AddRecord;
173 info->dom = mDNSfalse;
174
175 if (!AddRecord) // If TTL == 0 we're deleting a service,
176 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
177 else // else we're adding a new service
178 {
179 ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery));
180 if (!q) { OTFreeMem(info); services->lostRecords = true; return; }
181 mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services);
182 }
183 }
184
185 static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
186 {
187 #pragma unused (m)
188 #pragma unused (question)
189 SearcherServices *services = (SearcherServices *)question->QuestionContext;
190 linkedServiceInfo *info;
191
192 debugf("FoundDomain %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
193
194 if (answer->rrtype != kDNSType_PTR) return;
195 if (!services) { debugf("FoundDomain: services is NULL"); return; }
196
197 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
198 if (!info) { services->lostRecords = true; return; }
199
200 info->i.name = answer->rdata->u.name;
201 info->i.InterfaceID = answer->InterfaceID;
202 info->i.ip.type = mDNSAddrType_IPv4;
203 info->i.ip.ip.v4 = zerov4Addr;
204 info->i.port = zeroIPPort;
205 info->add = AddRecord;
206 info->dom = mDNStrue;
207
208 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
209 }
210
211 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
212 static Boolean YieldSomeTime(UInt32 milliseconds)
213 {
214 extern Boolean SIOUXQuitting;
215 EventRecord e;
216 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
217 SIOUXHandleOneEvent(&e);
218 return(SIOUXQuitting);
219 }
220
221 int main()
222 {
223 mStatus err;
224 Boolean DoneSetup = false;
225 void *tempmem;
226
227 SIOUXSettings.asktosaveonclose = false;
228 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
229 SIOUXSettings.rows = 40;
230 SIOUXSettings.columns = 132;
231
232 printf("Multicast DNS Searcher\n\n");
233 printf("This software reports errors using MacsBug breaks,\n");
234 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
235 printf("******************************************************************************\n");
236
237 err = InitOpenTransport();
238 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
239
240 err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
241 mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
242 if (err) return(err);
243
244 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
245 tempmem = OTAllocMem(0x10000);
246 if (tempmem) OTFreeMem(tempmem);
247 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
248
249 services.serviceinfolist.fHead = NULL;
250 services.headerPrinted = false;
251 services.lostRecords = false;
252
253 while (!YieldSomeTime(35))
254 {
255 #if MDNS_ONLYSYSTEMTASK
256 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
257 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
258 extern void mDNSPlatformIdle(mDNS *const m);
259 mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
260 #endif
261 if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
262 {
263 domainname srvtype, srvdom;
264 DoneSetup = true;
265 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
266 MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
267 MakeDomainNameFromDNSNameString(&srvdom, "local.");
268 err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, mDNSfalse, FoundInstance, &services);
269 if (err) break;
270 err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
271 if (err) break;
272 }
273
274 if (services.serviceinfolist.fHead)
275 PrintServiceInfo(&services);
276
277 if (services.lostRecords)
278 {
279 services.lostRecords = false;
280 printf("**** Warning: Out of memory: Records have been missed.\n");
281 }
282 }
283
284 mDNS_StopBrowse(&mDNSStorage, &browsequestion);
285 mDNS_Close(&mDNSStorage);
286 return(0);
287 }